// 14 重载运算与类型转换
/**
 * 当运算符被用于类类型的对象时，C++语言允许我们为其指定新的含义；同时，我们也能自定义类类型之间的转换规则。和内置类型的转换一样，类类型转换隐式地将一种类型的对象转换成另一种我们所需类型的对象。
 * 当运算符作用于类类型的运算对象时，可以通过运算符重载重新定义该运算符的含义。明智地使用运算符重载能令我们的程序更易于编写和阅读。
 */

#include <iterator>
#include <vector>
#include <list>
#include <deque>
#include <forward_list>
#include <string>
#include <array>
#include <stack>
#include <queue>
#include <algorithm>
#include <numeric>
using std::swap;
using std::vector, std::list, std::deque, std::forward_list, std::string, std::array, std::stack, std::queue;
#include "../Chapter07/Sales_data.h"
#include <iostream>
using std::begin, std::cbegin, std::end, std::cend, std::find, std::accumulate, std::equal, std::fill, std::fill_n, std::back_inserter;
using std::cin, std::cout, std::endl;
using std::copy, std::replace, std::replace_copy;
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <memory>
#include <new>
using namespace std;
#include "../Chapter13/13.5.cc" // 不能编译，因为重复定义的main函数

// 复合赋值运算符
// 作为成员的二元运算符，左侧运算对象绑定到隐式的this指针
// 假定两个对象表示的是同一本书
Sales_data& Sales_data::operator+=(const Sales_data &rhs)
{
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this;
}
// 假设两个对象指向同一本书
Sales_data
operator+(const Sales_data &lhs, const Sales_data &rhs)
{
    Sales_data sum = lhs; // 把lhs的数据拷贝给sum
    sum += rhs;           // 将rhs加到sum中
    return sum;
}

// 重载相等运算符
bool operator==(const Sales_data &lhs, const Sales_data &rhs)
{
    return lhs.isbn() == rhs.isbn() &&
           lhs.units_sold == rhs.units_sold &&
           lhs.revenue == rhs.revenue;
}
// 重载不相等运算符
bool operator!=(const Sales_data &lhs, const Sales_data &rhs)
{
    return !(lhs == rhs);
}

// 赋值运算符
StrVec &StrVec::operator=(initializer_list<std::string> il)
{
    // alloc_n_copy分配内存空间并从给定范围内拷贝元素
    auto data = alloc_n_copy(il.begin(), il.end());
    free();                // 销毁对象中的元素并释放内存空间
    elements = data.first; // 更新数据成员使其指向新空间
    first_free = cap = data.second;
    return *this;
}

int main()
{
    // 14.4 赋值运算符
    // 之前已经介绍过拷贝赋值和移动赋值运算符（参见13.1.2节，第443页和13.6.2节，第474页），它们可以把类的一个对象赋值给该类的另一个对象。
    // 此外，类还可以定义其他赋值运算符以使用别的类型作为右侧运算对象。
    // 举个例子，在拷贝赋值和移动赋值运算符之外，标准库vector类还定义了第三种赋值运算符，该运算符接受花括号内的元素列表作为参数（参见9.2.5节，第302页）。我们能以如下的形式使用该运算符：
    vector<string> v = {"a", "an", "the"};
    // 形参initializer_list<string>（参见6.2.6节，第198页）
    // 我们可以重载赋值运算符。不论形参的类型是什么，赋值运算符都必须定义为成员函数。

    // 复合赋值运算符
    // 复合赋值运算符不非得是类的成员，不过我们还是倾向于把包括复合赋值在内的所有赋值运算都定义在类的内部。
    // 为了与内置类型的复合赋值保持一致，类中的复合赋值运算符也要返回其左侧运算对象的引用。
    // 赋值运算符必须定义成类的成员，复合赋值运算符通常情况下也应该这样做。这两类运算符都应该返回左侧运算对象的引用。


    return 0;
}